package com.dlyk.config;

import com.dlyk.config.filter.TokenVerifyFilter;
import com.dlyk.config.handler.MyAccessDeniedHandler;
import com.dlyk.config.handler.MyAuthenticationFailureHandler;
import com.dlyk.config.handler.MyAuthenticationSuccessHandler;
import com.dlyk.config.handler.MyLogoutSuccessHandler;
import com.dlyk.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@EnableMethodSecurity   // 开启方法级别的权限检查
@Configuration
public class SecurityConfig {

    // 登录成功处理器
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    // 登录失败处理器
    @Resource
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    // token校验过滤器
    @Resource
    private TokenVerifyFilter tokenVerifyFilter;

    // 退出成功处理器
    @Resource
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    // 访问拒绝处理器
    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, CorsConfigurationSource corsConfigurationSource) throws Exception {

        return httpSecurity

                // 登录
                .formLogin( (formLogin) -> {
                    formLogin
                            .loginProcessingUrl(Constants.LOGIN_URI)   // 登录请求的url，交由Spring Security处理，不需要单独编写controller
                            .usernameParameter("loginAct")   // 用户名参数，默认是username，更改为loginAct（前端请求提交的参数名）
                            .passwordParameter("loginPwd")   // 密码参数，默认是password，更改为loginPwd（前端请求提交的参数名）
                            .successHandler(myAuthenticationSuccessHandler)  // 登录成功处理器
                            .failureHandler(myAuthenticationFailureHandler)  // 登录失败处理器
                            .permitAll();   // 放开登录请求的接口
                })

                // 请求认证
                .authorizeHttpRequests( (authorize) -> {
                    authorize
                            .anyRequest()       // 任何的请求
                            .authenticated();   // 都需要认证（登录后才能访问）
                })

                // 禁用跨站请求伪造
                .csrf( (csrf) -> {
                    csrf.disable();
                })

                // 支持跨域请求
                .cors( (cors) -> {
                    cors.configurationSource(corsConfigurationSource);
                })

                // session创建策略
                .sessionManagement( (session) -> {
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);  // 无状态session，也就是禁用session（使用JWT验证）
                })

                // 添加自定义的过滤器
                .addFilterBefore(tokenVerifyFilter, LogoutFilter.class)  // token校验过滤器添加到退出登录过滤器之前（退出之前也要校验token是否合法），token校验通过后表示该用户已登录

                // 退出登录
                .logout( (logout) -> {
                    logout
                          .logoutUrl(Constants.LOGOUT_URI)   // 退出登录请求的url，交由Spring Security处理，不需要单独编写controller
                          .logoutSuccessHandler(myLogoutSuccessHandler);  // 退出成功处理器
                })

                // 无权限访问时的处理（全局异常处理器的优先级更高）
                .exceptionHandling( (exceptionHandling) -> {
                    exceptionHandling.accessDeniedHandler(myAccessDeniedHandler);    // 访问拒绝处理器
                })

                // 构建
                .build();
    }

    /**
     * 密码编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 跨域支持
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {

        // 跨域配置
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 设置允许请求来源，任何来源
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));    // http://127.0.0.1:8081
        // 设置允许请求方法，任何方法
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));    // get、post、put、delete
        // 设置允许请求头，任何请求头
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));    // 允许任何请求头

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        // 注册跨域配置
        // /** 表示任何请求路径，都使用以上跨域配置
        source.registerCorsConfiguration("/**", corsConfiguration);

        return source;
    }

}

